#include <iostream>
#include <pthread.h>
#include <unistd.h>

using namespace std;


//Task：多线程抢票
//      创建4个线程，让它们并发的访问ticks，进行抢票(--操作)，观察现象，并解决问题

// int tickets = 5000;
// pthread_mutex_t mutex; //定义一个互斥锁
// // pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; //这样初始化锁，就不需要对锁进行pthread_mutex_destroy


// //线程的入口函数
// void* threadRoutine(void* args)
// {
//     char* name = static_cast<char *>(args);  //将类型安全转换
//     while(true)
//     {
//         pthread_mutex_lock(&mutex);
//         if(tickets > 0)
//         {
//             usleep(1000); // 抢票相关操作
//             cout << name << " get a ticket " << tickets-- << endl;
//             pthread_mutex_unlock(&mutex);
//         }
//         else
//         {
//             pthread_mutex_unlock(&mutex);
//             break;
//         }
//         // pthread_mutex_unlock(&mutex); //error,放在这里是不对的，因为如果直接break的话，锁就没有被释放
//         usleep(500); //抢到票后的相关操作
//     }
//     return nullptr;
// }

// int main()
// {
//     pthread_mutex_init(&mutex, nullptr); //对互斥锁进行初始化

//     pthread_t t[4] = {0};
//     for(int i = 0; i < 4; i++)
//     {
//         char* name = new char[64];
//         snprintf(name,64,"%s-%d","thread",i);
//         pthread_create(t + i,nullptr,threadRoutine, name);
//     }

//     //等待子线程结束，并回收它们
//     for(int i = 0; i < 4; i++)
//     {
//         // pthread_detach() // 主线程分离，用错函数了
//         pthread_join(t[i],nullptr);
//     }
//     pthread_mutex_destroy(&mutex); //对互斥锁进行销毁
//     return 0;
// }

// 现象：不加锁的情况下，我们可以看到，票数会出现负数，这就是因为多线程并发访问造成的后果
// 当加上锁后，对临界资源的访问从并发变为了串行访问，速度变慢了，但是更安全了



//-------------------------------------------------------------------------------------
//对上述代码进行改进，加上一些封装


int tickets = 5000;

class ThreadData
{
public:
    ThreadData(string name = "",pthread_mutex_t* pmutex = nullptr)
    :_name(name),
    _pmutex(pmutex)
    {}
    
    ~ThreadData()
    {}
 
    string _name;
    pthread_mutex_t* _pmutex;
};

//线程的入口函数
void* threadRoutine(void* args)
{
    ThreadData* td = static_cast<ThreadData *>(args);  //将类型安全转换
    while(true)
    {
        pthread_mutex_lock(td->_pmutex);
        if(tickets > 0)
        {
            usleep(1000); // 抢票相关操作
            cout << td->_name << " get a ticket " << tickets-- << endl;
            pthread_mutex_unlock(td->_pmutex);
        }
        else
        {
            pthread_mutex_unlock(td->_pmutex);
            // break;
        }
        // pthread_mutex_unlock(&mutex); //error,放在这里是不对的，因为如果直接break的话，锁就没有被释放
        usleep(500); //抢到票后的相关操作
    }
    return nullptr;
}

int main()
{
    pthread_mutex_t mutex; //定义一个互斥锁
    pthread_mutex_init(&mutex, nullptr); //对互斥锁进行初始化

    pthread_t t[4] = {0};
    for(int i = 0; i < 4; i++)
    {
        char name[64] = { 0 };
        snprintf(name,64,"%s-%d","thread",i);
        ThreadData* td = new ThreadData(name,&mutex);
        pthread_create(t + i,nullptr,threadRoutine, td);
    }

    //等待子线程结束，并回收它们
    for(int i = 0; i < 4; i++)
    {
        // pthread_detach() // 主线程分离，用错函数了
        pthread_join(t[i],nullptr);
    }
    pthread_mutex_destroy(&mutex); //对互斥锁进行销毁
    return 0;
}



// -----------------------------------------------------------------------------------

